package edu.hcmus.sow.service;

import java.util.Calendar;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import edu.hcmus.sow.dao.ClientDAO;
import edu.hcmus.sow.dao.FileAccessRightDAO;
import edu.hcmus.sow.dao.FileDAO;
import edu.hcmus.sow.dao.FileRevisionCommentDAO;
import edu.hcmus.sow.dao.FileRevisionDAO;
import edu.hcmus.sow.dao.FolderDAO;
import edu.hcmus.sow.domain.Client;
import edu.hcmus.sow.domain.File;
import edu.hcmus.sow.domain.FileAccessRight;
import edu.hcmus.sow.domain.FileRevision;
import edu.hcmus.sow.domain.FileRevisionComment;
import edu.hcmus.sow.domain.Folder;
import edu.hcmus.sow.domain.User;
import edu.hcmus.sow.utils.SecurityUtil;

@Service
@Transactional
public class DocumentService {
   // ~ Instance fields
   // ================================================================================================
   @Autowired
   private FolderDAO folderDAO;

   @Autowired
   private FileRevisionDAO fileRevisionDAO;

   @Autowired
   private FileDAO fileDAO;

   @Autowired
   private ClientDAO clientDAO;

   @Autowired
   private UserService userService;

   @Autowired
   private FileRevisionCommentDAO fileRevisionCommentDAO;

   @Autowired
   private FileAccessRightDAO fileAccessRightDAO;

   // ~ Repository's methods
   // ================================================================================================
   public List<Folder> getAuthorizedRepositories(Integer clientID) {
      return folderDAO.getByClientID(clientID); // test with clientID=1
   }

   public List<Folder> getRepositories() {
      return folderDAO.getRepositories(SecurityUtil.getCurrentClient());
   }

   public Folder saveRepository(Integer id, String name, String description) {
      User user = userService.getUserByID(SecurityUtil.getCurrentLoggedinUserID());
      Folder folder = id == null ? new Folder() : folderDAO.findById(id);
      folder.setName(name);
      folder.setDescription(description);

      folder.setUpdatedDate(Calendar.getInstance());
      folder.setUserByUpdatedBy(user);

      if (id == null) {
         folder.setClient(clientDAO.findById(SecurityUtil.getCurrentClient()));
         folder.setCreatedDate(Calendar.getInstance());
         folder.setUserByCreatedBy(user);
         folder = folderDAO.persist(folder);
      }
      return folder;
   }

   // ~ Folder's methods
   // ================================================================================================
   public List<Folder> getFoldersByParentID(Integer parentID) {
      List<Folder> list = folderDAO.getByParentID(parentID);
      return list;
   }

   public Folder saveFolder(Folder folder) {
      if (folder.getId() != null) {
         folder = folderDAO.merge(folder);
      } else {
         folder = folderDAO.persist(folder);
      }

      return folder;
   }

   public Folder getFolderByID(Integer folderID) {
      Folder folder = folderDAO.findById(folderID);
      return folder;
   }

   public void deleteFolder(Integer folderID) {
      Folder folder = folderDAO.findById(folderID);
      if (folder != null)
         folderDAO.delete(folder);
   }

   public boolean folderExists(Integer clientID, Integer parentID, String name) {
      return folderDAO.isExist(clientID, parentID, name);
   }

   public Integer createFolder(Integer parentID, String folderName) {
      // get current client
      int clientID = SecurityUtil.getCurrentClient();
      Client client = clientDAO.findById(clientID);

      // get logged in user
      int userID = SecurityUtil.getCurrentLoggedinUserID();
      User user = userService.getUserByID(userID);

      // get parent folder
      Folder parentFolder = getFolderByID(parentID);

      Folder folder = new Folder();

      folder.setFolder(parentFolder);
      folder.setName(folderName.trim());
      folder.setClient(client);
      folder.setCreatedDate(Calendar.getInstance());
      folder.setUserByCreatedBy(user);
      folder.setUpdatedDate(Calendar.getInstance());
      folder.setUserByUpdatedBy(user);
      folder.setStatus("A");

      folder = saveFolder(folder);
      return folder.getId();
   }

   public boolean renameFolder(Folder folder, String name) {
      try {
         // get logged in user
         int userID = SecurityUtil.getCurrentLoggedinUserID();
         User user = userService.getUserByID(userID);

         folder.setName(name.trim());
         folder.setUpdatedDate(Calendar.getInstance());
         folder.setUserByUpdatedBy(user);

         folder = saveFolder(folder);
      } catch (Exception e) {
         return false;
      }
      return true;
   }

   // ~ File's method
   // ================================================================================================
   public boolean fileExists(Integer folderID, String name) {
      return fileDAO.isExist(folderID, name);
   }

   public File getFileByID(Integer id) {
      return fileDAO.findById(id);
   }

   public File saveFile(File file) {
      if (file.getId() != null) {
         file = fileDAO.merge(file);
      } else {
         file = fileDAO.persist(file);
      }

      return file;
   }

   public void deleteFile(Integer fileID) {
      File file = fileDAO.findById(fileID);
      if (file != null)
         fileDAO.delete(file);
   }

   public File findFileByName(String fileName) {
      File file = fileDAO.findByName(fileName);
      return file;
   }

   // ~ FileRevision's method
   // ================================================================================================
   public List<FileRevision> getLatestFilesVersionByFolderID(Integer folderID) {
      List<FileRevision> list = fileRevisionDAO.getLatestVersionByFolderID(folderID);
      return list;
   }

   public FileRevision getFileRevisionByID(Integer id) {
      return fileRevisionDAO.findById(id);
   }

   public FileRevision saveFileRevision(FileRevision fileRevision) {
      if (fileRevision.getId() != null) {
         fileRevision = fileRevisionDAO.merge(fileRevision);
      } else {
         fileRevision = fileRevisionDAO.persist(fileRevision);
      }
      return fileRevision;
   }

   public List<FileRevision> getFilesRevisionByFileID(Integer fileID) {
      List<FileRevision> list = fileRevisionDAO.getRevisionsListByFileID(fileID);
      return list;
   }

   // ~ FileRevisionComment's method
   // ================================================================================================
   public List<FileRevisionComment> getCommentsByFileRevisionID(Integer fileRevisionID) {
      List<FileRevisionComment> list = fileRevisionCommentDAO.getByFileRevisionID(fileRevisionID);
      return list;
   }

   public FileRevisionComment saveFileRevisionComment(FileRevisionComment fileRevisionComment) {
      if (fileRevisionComment.getId() != null) {
         fileRevisionComment = fileRevisionCommentDAO.merge(fileRevisionComment);
      } else {
         fileRevisionComment = fileRevisionCommentDAO.persist(fileRevisionComment);
      }
      return fileRevisionComment;
   }

   // ~ FileAccessRight's method
   // ================================================================================================
   public FileAccessRight getPermissionByID(Integer id) {
      FileAccessRight far = fileAccessRightDAO.findById(id);
      return far;
   }

   public List<FileAccessRight> getPermissionsByFileID(Integer fileID) {
      List<FileAccessRight> list = fileAccessRightDAO.getByFileID(fileID);
      return list;
   }

   public FileAccessRight saveFileAccessRight(FileAccessRight far) {
      if (far.getId() != null) {
         far = fileAccessRightDAO.merge(far);
      } else {
         far = fileAccessRightDAO.persist(far);
      }

      return far;
   }

   public void deleteFileAccessRight(Integer id) {
      FileAccessRight far = getPermissionByID(id);
      if (far != null) {
         fileAccessRightDAO.delete(far);
      }
   }

   public FileAccessRight findOrCreatePermission(Integer fileID, Integer userID) {
      FileAccessRight far = fileAccessRightDAO.findByFileAndUser(fileID, userID);
      if (far == null) {
         return new FileAccessRight();
      }
      return far;
   }

   public FileAccessRight findByFileAndUser(Integer fileID, Integer userID) {
      return fileAccessRightDAO.findByFileAndUser(fileID, userID);
   }

   public String getAccessRightByFile(File f) {
      FileAccessRight far = findByFileAndUser(f.getId(), SecurityUtil.getCurrentLoggedinUserID());
      return far == null ? f.getDefaultAccessRight() : far.getAccessRight();
   }
}
